home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
rpg
/
crossfir.92
/
crossfir
/
crossfire-0.92.5
/
server
/
c_object.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-24
|
19KB
|
792 lines
/*
* Object (handling) commands
* ++Jam & Anipa
*/
#include <global.h>
#include <loader.h>
#include <sproto.h>
/*
* Object id parsing functions
*/
#define OBLINKMALLOC(p) if(!((p)=(objectlink *)malloc(sizeof(objectlink))))\
fatal(OUT_OF_MEMORY);
#define ADD_ITEM(NEW,COUNT)\
if(!first) {\
OBLINKMALLOC(first);\
last=first;\
} else {\
OBLINKMALLOC(last->next);\
last=last->next;\
}\
last->next=NULL;\
last->ob=(NEW);\
last->id=(COUNT);
/* returns nonzero if the appropriate action can be
* done. Really a stupid function - this should be handled in
* the calling function.
*/
static int may_do(object *op,object *ob,int state)
{
if(!ob)
return 0;
switch(state)
{
case 0: /* drop */
return (!QUERY_FLAG(ob,FLAG_NO_DROP) && !ob->invisible);
case 1: /* take */
return (can_pick(op,ob) && !ob->invisible);
default:
return 0;
}
}
static objectlink *parse_id(object *op,object *from, char *name, int state)
{
objectlink *first=NULL,*last=NULL;
int count=0,plural=0;
char buf[MAX_BUF];
while(name[0]==' ') /* get rid of leading spaces ', ' */
name++;
if(strcmp(name,"all")==0)
{
while(from)
{
if(may_do(op,from,state))
{
ADD_ITEM(from,0);
}
from=from->below;
}
return first;
}
if(strcmp(name,"unpaid")==0)
{
while(from)
{
if(QUERY_FLAG(from,FLAG_UNPAID) && may_do(op,from,state))
{
ADD_ITEM(from,0);
}
from=from->below;
}
return first;
}
if((count=atoi(name))!=0)
name=strchr(name,' ');
else
if (op->contr->count>0 && op->contr->count<10000)
count=op->contr->count;
if(!name || strlen(name)==0 || count<0)
return NULL;
while(name[0]==' ') /* get rid of leading spaces ', ' */
name++;
if(strlen(name)==0)
return NULL;
while(from)
{
if(may_do(op,from,state))
{
strcpy(buf,from->name);
if(QUERY_FLAG(from, FLAG_NEED_IE)) {
char *cp=strrchr(buf,'y');
if(cp!=NULL)
*cp='\0'; /* Strip the 'y' */
strcat(buf,"ies");
} else
strcat(buf,"s");
if(strcasecmp(name,from->name)==0 && count<2) /* singular */
{
ADD_ITEM(from,1);
break;
}
else if(strcasecmp(name,buf)==0 && (count!=1 || plural)) /* plural */
{
plural=1;
ADD_ITEM(from,count);
count-=(from->nrof<1?1:from->nrof);
if(count<=0)
{
count=0;
break;
}
}
else if(strcasecmp(name,query_name(from))==0 && count==0)
{
ADD_ITEM(from,from->nrof);
}
}
from=from->below;
}
return first;
}
objectlink *id(object *op,object *from,char *ids,int state)
{
objectlink *first=NULL,*last=NULL,*tmp;
char *name;
if(from==NULL)
return NULL;
if(ids==NULL || !ids[0])
{
while(from && from->invisible && may_do(op, from, state))
from=from->below;
if(!from)
return NULL;
OBLINKMALLOC(first);
first->ob=from;
first->id=op->contr->count;
first->next=NULL;
return first;
}
name=strtok(ids,","); /* pearls, gems, coins (split with commas) */
while(name)
{
if((tmp=parse_id(op,from,name,state)))
{
if(!first)
first=tmp;
else
last->next=tmp;
last=tmp;
while(last->next) /* move to end of list */
last=last->next;
}
name=strtok(NULL,",");
}
if(first && first->next) /* get rid of duplicates */
{
objectlink *pos,*prev;
pos=first;
while(pos)
{
tmp=pos->next;
prev=pos;
while(tmp)
{
if(tmp->ob == pos->ob)
{
if(tmp->id==0 || pos->id==0)
pos->id=0;
else
pos->id=pos->id + tmp->id;
prev->next=tmp->next;
free(tmp);
tmp=prev->next;
}
else
{
prev=tmp;
tmp=tmp->next;
}
}
pos=pos->next;
}
}
return first;
}
int command_uskill ( object *pl, char *params) {
if (!params) {
new_draw_info(NDI_UNIQUE, 0,pl, "Usage: use_skill <skill name>");
return 0;
}
return use_skill(pl,params);
}
int command_rskill ( object *pl, char *params) {
if (!params) {
new_draw_info(NDI_UNIQUE, 0,pl, "Usage: ready_skill <skill name>");
return 0;
}
return change_skill(pl,lookup_skill_by_name(params));
}
int command_apply (object *op, char *params)
{
if (!params) {
apply_below(op);
return 0;
}
apply_inventory(op);
/* By applying something what, the applied/unapplied state will change,
* so the window needs to be updated.
*/
if (op->contr->show_what == show_applied || op->contr->show_what==show_unapplied)
draw_all_inventory(op);
return 0;
}
/* Pick up commands follow */
/* pl = player, op is the object to put tmp into,
* tmp is the object to pick up, nrof is the number to
* pick up (0 means all of them)
*/
void pick_up_object (object *pl, object *op, object *tmp, int nrof)
{
char buf[MAX_BUF];
if(QUERY_FLAG(pl, FLAG_FLYING) && !QUERY_FLAG(pl, FLAG_WIZ)) {
new_draw_info(NDI_UNIQUE, 0,pl, "You are levitating, you can't reach the ground!");
return;
}
if(!can_pick(pl,tmp)) {
if (tmp->name!=NULL) {
sprintf(buf,"You can't pick up a %s", tmp->name);
new_draw_info(NDI_UNIQUE, 0,pl, buf);
}
else
new_draw_info(NDI_UNIQUE, 0,pl,"You can't take that!");
return;
}
if (QUERY_FLAG (tmp, FLAG_NO_DROP))
return;
if(QUERY_FLAG(tmp,FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
new_draw_info(NDI_UNIQUE, 0,pl, "The object disappears in a puff of smoke!");
new_draw_info(NDI_UNIQUE, 0,pl, "It must have been an illusion.");
if (pl->contr->eric_server > 0)
esrv_del_item (pl->contr->eric_server, tmp->count);
remove_ob(tmp);
free_object(tmp);
return;
}
if(QUERY_FLAG(pl, FLAG_WAS_WIZ))
SET_FLAG(tmp, FLAG_WAS_WIZ);
if(nrof && nrof != tmp->nrof) {
object *tmp2 = tmp;
tmp = get_split_ob (tmp, nrof);
if(!tmp) {
new_draw_info(NDI_UNIQUE, 0,pl, errmsg);
return;
}
/* Tell a client what happened rest of objects */
if (pl->contr->eric_server > 0)
if (QUERY_FLAG(tmp2, FLAG_REMOVED))
esrv_del_item (pl->contr->eric_server, tmp2->count);
else
esrv_send_item (pl, tmp2);
} else {
remove_ob(tmp); /* Unlink it */
}
if(QUERY_FLAG(tmp, FLAG_UNPAID))
(void) sprintf(buf,"%s will cost you %s.", query_name(tmp),
query_cost_string(tmp,op,F_BUY));
else
(void) sprintf(buf,"You pick up %s.", query_name(tmp));
new_draw_info(NDI_UNIQUE, 0,op,buf);
tmp = insert_ob_in_ob(tmp, op);
if(pl->type!=PLAYER) return;
if (pl->contr->eric_server > 0) {
esrv_send_item (pl, tmp);
} else {
pl->contr->last_used=tmp;
pl->contr->last_used_id=tmp->count;
draw_inventory(pl);
if (pl->container)
draw_look (pl);
}
}
void pick_up(object *op,object *alt)
/* modified slightly to allow monsters use this -b.t. 5-31-95 */
{
object *tmp=NULL;
int count;
if(alt)
tmp=alt;
else if(op->below==NULL || !can_pick(op, tmp)) {
new_draw_info(NDI_UNIQUE, 0,op,"There is nothing to pick up here.");
return;
} else
tmp=op->below;
if (op->type==PLAYER && op->contr->count && op->contr->count <tmp->nrof)
count=op->contr->count;
else
count=tmp->nrof;
/* container is open, so use it */
if (op->container) {
alt = op->container;
if (alt != tmp->env && !sack_can_hold (op, alt, tmp,count))
return;
} else {
for (alt=op->inv; alt; alt=alt->below)
if (alt->type==CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) &&
alt->race && alt->race==tmp->race &&
sack_can_hold (NULL, alt, tmp,count))
break; /* perfect match */
if (!alt)
for (alt=op->inv; alt; alt=alt->below)
if (alt->type==CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) &&
sack_can_hold (NULL, alt, tmp,count))
break; /* General container comes next */
if (!alt)
alt = op; /* No free containers */
}
if(tmp->env == alt) {
/* here it could be possible to check rent,
* if someone wants to implement it
*/
alt = op;
}
#ifdef PICKUP_DEBUG
printf ("Pick_up(): %s picks %s (%d) and inserts it %s.\n",op->name, tmp->name, op->contr->count, alt->name);
#endif
if(op->type==PLAYER) {
pick_up_object(op, alt, tmp, op->contr->count);
op->contr->count=0;
} else
pick_up_object(op, alt, tmp, tmp->nrof);
}
int command_take (object *op, char *params)
{
object *tmp=op->below, *next;
if (tmp==NULL) {
new_draw_info(NDI_UNIQUE, 0,op,"Nothing to take!");
return 0;
}
/* Makes processing easier */
if (params && *params=='\0') params=NULL;
op->contr->freeze_inv=1;
op->contr->freeze_look=1;
while (tmp) {
next=tmp->below;
if (tmp->invisible) {
tmp=next;
continue;
}
/* This following two if and else if could be merged into line
* but that probably will make it more difficult to read, and
* not make it any more efficient
*/
if (params && !strncasecmp(params, tmp->name, strlen(params))) {
pick_up(op, tmp);
}
else if (can_pick(op, tmp) && !params) {
pick_up(op,tmp);
break;
}
tmp=next;
}
if (!params && !tmp) {
for (tmp=op->below; tmp!=NULL; tmp=tmp->next)
if (!tmp->invisible) {
char buf[MAX_BUF];
sprintf(buf,"You can't pick up a %s",
tmp->name? tmp->name:"null");
new_draw_info(NDI_UNIQUE, 0,op, buf);
break;
}
if (!tmp) new_draw_info(NDI_UNIQUE, 0,op, "There is nothing to pick up.");
}
op->contr->freeze_inv=0;
op->contr->freeze_look=0;
draw_inventory(op);
draw_look(op);
return 0;
}
/*
* This function was part of drop, now is own function.
* Player 'op' tries to put object 'tmp' into sack 'sack',
* if tmp is non zero, then nrof objects is tried to put into sack.
*/
void put_object_in_sack (object *op, object *sack, object *tmp, long nrof)
{
object *tmp2;
char buf[MAX_BUF];
if (sack==tmp) return; /* Can't put an object in itself */
if (sack->type != CONTAINER) {
new_draw_info_format(NDI_UNIQUE, 0,op,
"%s is not a container.", query_name(sack));
return;
}
if (QUERY_FLAG(tmp,FLAG_STARTEQUIP)) {
new_draw_info_format(NDI_UNIQUE, 0,op,
"You cannot put %s in the container.", query_name(tmp));
return;
}
if (tmp->type == CONTAINER && tmp->inv) {
/* Eneq(@csd.uu.se): If the object to be dropped is a container
* we instead move the contents of that container into the active
* container, this is only done if the object has something in it.
*/
sprintf (buf, "You move the items from %s into ", query_name(tmp));
strcat (buf, query_name(op->container));
strcat (buf, ".");
new_draw_info(NDI_UNIQUE, 0,op, buf);
for (tmp2 = tmp->inv; tmp2; tmp2 = tmp) {
tmp = tmp2->below;
if (sack_can_hold(op, op->container, tmp2,tmp2->nrof))
put_object_in_sack (op, sack, tmp2, 0);
else {
sprintf(buf,"Your %s fills up.", query_name(op->container));
new_draw_info(NDI_UNIQUE, 0,op, buf);
break;
}
}
return;
}
if (! sack_can_hold (op, sack, tmp,(nrof?nrof:tmp->nrof)))
return;
/* Small hack to avoid autojoining in apply_special(): */
if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
int nrof = tmp->nrof, a;
tmp->nrof = 0;
a = apply_special(op,tmp);
tmp->nrof = nrof;
if (a)
return;
}
if (nrof && tmp->nrof != nrof) {
object *tmp2 = tmp;
tmp = get_split_ob (tmp, nrof);
if(!tmp) {
new_draw_info(NDI_UNIQUE, 0,op, errmsg);
return;
}
/* Tell a client what happened other objects */
if (op->contr->eric_server > 0)
if (QUERY_FLAG(tmp2, FLAG_FREED))
esrv_del_item (op->contr->eric_server, tmp2->count);
else
esrv_send_item (op, tmp2);
} else
remove_ob(tmp);
sprintf(buf, "You put %s in ", query_name(tmp));
strcat (buf, query_name(sack));
strcat (buf, ".");
tmp = insert_ob_in_ob(tmp, sack);
new_draw_info(NDI_UNIQUE, 0,op,buf);
if (op->contr->eric_server > 0) {
esrv_send_item (op, tmp);
} else {
draw_look(op);
draw_inventory(op);
}
fix_player(op); /* This is overkill, fix_player() is called somewhere */
/* in object.c */
}
/*
* This function was part of drop, now is own function.
* Player 'op' tries to drop object 'tmp', if tmp is non zero, then
* nrof objects is tried to dropped.
*/
void drop_object (object *op, object *tmp, long nrof)
{
char buf[MAX_BUF];
object *floor;
if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
#if 0
/* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
new_draw_info(NDI_UNIQUE, 0,op, "This item can't be dropped.");
#endif
return;
}
/* Small hack to avoid autojoining in apply_special(): */
if(QUERY_FLAG(tmp, FLAG_APPLIED)) {
int nrof = tmp->nrof,a;
tmp->nrof = 0;
a = apply_special (op, tmp);
tmp->nrof = nrof;
if (a) /* can't unapply it */
return;
}
if(nrof && tmp->nrof != nrof) {
object *tmp2 = tmp;
tmp = get_split_ob (tmp, nrof);
if(!tmp) {
new_draw_info(NDI_UNIQUE, 0,op, errmsg);
return;
}
/* Tell a client what happened rest of objects */
if (op->contr->eric_server > 0)
if (QUERY_FLAG(tmp2, FLAG_FREED))
esrv_del_item (op->contr->eric_server, tmp->count);
else
esrv_send_item (op, tmp);
} else
remove_ob (tmp);
if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) {
sprintf(buf,"You drop %s.", query_name(tmp));
new_draw_info(NDI_UNIQUE, 0,op,buf);
new_draw_info(NDI_UNIQUE, 0,op,"The gods who lent it to you retrieves it.");
if (op->contr->eric_server > 0)
esrv_del_item (op->contr->eric_server, tmp->count);
free_object(tmp);
fix_player(op);
return;
}
/* If SAVE_INTERVAL is commented out, we never want to save
* the player here.
*/
#ifdef SAVE_INTERVAL
if (!QUERY_FLAG(tmp, FLAG_UNPAID) &&
(tmp->nrof ? tmp->value * tmp->nrof : tmp->value > 2000))
#if SAVE_INTERVAL
if((op->contr->last_save_time + SAVE_INTERVAL) <= time(NULL)) {
save_player(op, 1);
op->contr->last_save_time = time(NULL);
}
#else
save_player(op,1); /* To avoid cheating */
#endif
#endif /* SAVE_INTERVAL */
D_LOCK(op);
floor = get_map_ob (op->map, op->x, op->y);
if( floor && floor->type == SHOP_FLOOR &&
!QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY)
sell_item(tmp,op);
tmp->x = op->x;
tmp->y = op->y;
insert_ob_in_map(tmp, op->map);
remove_ob(op);
insert_ob_in_map(op, op->map);
D_UNLOCK(op);
if (op->contr->eric_server > 0) {
esrv_send_item (op, tmp);
} else {
draw_look(op);
draw_inventory(op);
}
fix_player(op); /* This is overkill, fix_player() is called somewhere */
/* in object.c */
#ifdef USE_LIGHTING
if(tmp->glow_radius>0) remove_light_from_list(tmp,op);
#endif
}
void drop(object *op, object *tmp)
{
while(tmp!=NULL && tmp->invisible)
tmp=tmp->below;
if (tmp==NULL) {
new_draw_info(NDI_UNIQUE, 0,op,"You don't have anything to drop.");
return;
}
if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
new_draw_info(NDI_UNIQUE, 0,op,"This item is locked");
return;
}
if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
#if 0
/* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
new_draw_info(NDI_UNIQUE, 0,op, "This item can't be dropped.");
#endif
return;
}
if (op->contr->last_used==tmp && op->contr->last_used_id == tmp->count) {
object *n=NULL;
if(tmp->below != NULL)
n = tmp->below;
else if(tmp->above != NULL)
n = tmp->above;
op->contr->last_used = n;
if (n != NULL)
op->contr->last_used_id = n->count;
else
op->contr->last_used_id = 0;
}
if (op->container) {
put_object_in_sack (op, op->container, tmp, op->contr->count);
} else {
drop_object (op, tmp, op->contr->count);
}
op->contr->count = 0;
}
/* Command will drop all items that have not been locked */
int command_dropall (object *op, char *params) {
object * curinv, *nextinv;
if(op->inv == NULL) {
new_draw_info(NDI_UNIQUE, 0,op,"Nothing to drop!");
return 0;
}
curinv = op->inv;
op->contr->freeze_inv=1;
op->contr->freeze_look=1;
/*
This is the default. Drops everything not locked or considered
not something that should be dropped.
*/
/*
Care must be taken that the next item pointer is not to money as
the drop() routine will do unknown things to it when dropping
in a shop. --Tero.Pelander@utu.fi
*/
if(params==NULL) {
while(curinv != NULL) {
nextinv = curinv->below;
while (nextinv && nextinv->type==MONEY)
nextinv = nextinv->below;
if(! QUERY_FLAG(curinv,FLAG_INV_LOCKED) && curinv->type != MONEY &&
curinv->type != FOOD && curinv->type != KEY &&
curinv->type != SPECIAL_KEY && curinv->type != GEM &&
!curinv->invisible &&
(curinv->type!=CONTAINER || op->container!=curinv))
{
drop(op,curinv);
}
curinv = nextinv;
}
}
else if(strcmp(params, "weapons") == 0) {
while(curinv != NULL) {
nextinv = curinv->below;
while (nextinv && nextinv->type==MONEY)
nextinv = nextinv->below;
if(! QUERY_FLAG(curinv,FLAG_INV_LOCKED) && ((curinv->type == WEAPON) ||
(curinv->type == BOW) || (curinv->type == ARROW)))
{
drop(op,curinv);
}
curinv = nextinv;
}
}
else if(strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
while(curinv != NULL) {
nextinv = curinv->below;
while (nextinv && nextinv->type==MONEY)
nextinv = nextinv->below;
if(! QUERY_FLAG(curinv,FLAG_INV_LOCKED) && ((curinv->type == ARMOUR) ||
curinv->type == SHIELD || curinv->type==HELMET))
{
drop(op,curinv);
}
curinv = nextinv;
}
}
else if(strcmp(params, "misc") == 0) {
while(curinv != NULL) {
nextinv = curinv->below;
while (nextinv && nextinv->type==MONEY)
nextinv = nextinv->below;
if(! QUERY_FLAG(curinv,FLAG_INV_LOCKED) && ! QUERY_FLAG(curinv,FLAG_APPLIED)) {
switch(curinv->type) {
case HORN:
case BOOK:
case SPELLBOOK:
case GIRDLE:
case AMULET:
case RING:
case CLOAK:
case BOOTS:
case GLOVES:
case BRACERS:
case SCROLL:
case ARMOUR_IMPROVER:
case WEAPON_IMPROVER:
case WAND:
case ROD:
case POTION:
drop(op,curinv);
curinv = nextinv;
break;
default:
curinv = nextinv;
break;
}
}
curinv = nextinv;
}
}
op->contr->freeze_inv=0;
op->contr->freeze_look=0;
draw_all_inventory(op);
draw_look(op);
return 0;
}
int command_drop (object *op, char *params)
{
objectlink *list,*tmp;
list=id(op,op->inv,params,0);
if(!list)
{
new_draw_info(NDI_UNIQUE, 0,op,"Nothing to drop!");
return 0;
}
op->contr->freeze_inv=1;
op->contr->freeze_look=1;
while(list)
{
op->contr->count=list->id;
drop(op,list->ob);
tmp=list->next;
free(list);
list=tmp;
}
op->contr->freeze_inv=0;
op->contr->freeze_look=0;
op->contr->count=0;
draw_all_inventory(op);
draw_look(op);
return 0;
}
int command_examine (object *op, char *params)
{
if (!params)
examine(op,op->below);
else
examine(op,op->inv);
return 0;
}